package net.xuele.learn.concurrent;

import cn.hutool.core.thread.NamedThreadFactory;
import org.junit.Before;
import org.junit.Test;

import java.util.Map;
import java.util.concurrent.*;

/**
 * @Author patrick
 * @Date 2022/8/22 19:11
 * @Description
 */
public class TestVolatile {
    private volatile Map<String, Boolean> map = new ConcurrentHashMap<>();

    private volatile Boolean[] arr = new Boolean[2];

    @Before
    public void before() {
        map.put("1", true);
        arr[0] = true;
        arr[1] = false;
    }

    @Test
    public void test1() throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 10,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(50), new NamedThreadFactory("test-", false));

        executor.execute(() -> {
            while (map.get("1")) {
                System.out.println(Thread.currentThread().getName() + "----------------");
            }
            System.out.println("==========");
        });

        executor.execute(() -> {
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(300);
                map.put("1", false);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "=====");
        });

        executor.execute(() -> {
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(300);
                map.put("1", false);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            map = new ConcurrentHashMap<>();
            map.put("1", false);
            System.out.println(Thread.currentThread().getName() + "=====");
        });
        new CountDownLatch(1).await();
    }

    @Test
    public void test2() throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 10,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(50), new NamedThreadFactory("test-", false));

        executor.execute(() -> {
            while (arr[0]) {
                System.out.println(Thread.currentThread().getName() + "----------------");
            }
            System.out.println("==========");
        });

        executor.execute(() -> {
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(100);
                map.put("1", false);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            arr[0] = false;
            System.out.println(Thread.currentThread().getName() + "=====");
        });
        new CountDownLatch(1).await();
    }


    // fixme 当一个线程在读取一个使用volatile修饰的变量的时候，会将该线程中所有使用的变量从主内存中重新读取
    private volatile int val = 0;

    @Test
    public void test3() throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 10,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(50), new NamedThreadFactory("test-", false));

        executor.execute(() -> {
            while (true) {
                int i = val;
                if (arr[1]) {
                    break;
                }
            }
            System.out.println("==========");
        });

        executor.execute(() -> {
            try {
                Thread.sleep(100);
                arr[1] = true;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        new CountDownLatch(1).await();
    }


    /**
     * synchronized关键字也能够使得变量重新从内存中读取
     * 线程获取锁，需要将清空工作内存中共享变量的值，从主存中重新获取。而释放锁前，需要将自身变量值同步回主存
     */
    private int q = 3;
    @Test
    public void test4() throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 10,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(50), new NamedThreadFactory("test-", false));
        executor.execute(() -> {
            while (q == 3) {
                synchronized (this) {

                }

            }
            System.out.println("==========");
        });
        executor.execute(() -> {
            try {
                Thread.sleep(100);
                q = 4;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        new CountDownLatch(1).await();
    }
}
